using System;
using System.Collections.Generic;
using System.Text;
using Castle.DynamicProxy;
using Sio.Mdm.Types;
using Castle.Core.Interceptor;

namespace Sio.Mdm.Server
{
    /// <summary>
    /// Manager for handling security and <see cref="ISecurityHandler"/>. Note that
    /// security can only be handled on server side. So if you use remoting server
    /// you must implement and register all security handlers where you host your
    /// remoting server.
    /// </summary>
    public static class SecurityManager
    {
        #region Properties

        #region Public

        #region Handlers
        private static List<ISecurityHandler> _handlers = new List<ISecurityHandler>();
        public static IList<ISecurityHandler> Handlers
        {
            get
            {
                return _handlers.AsReadOnly();
            }
        }
        #endregion

        #endregion

        #endregion

        #region Methods

        #region Public
        /// <summary>
        /// Register <see cref="ISecurityHandler"/> implementation. This will get called
        /// when security check should be performed.
        /// </summary>
        /// <param name="handler">Instace of <see cref="ISecurityHandler"/> implementation</param>
        /// <returns>True if registered false if handler is already registered</returns>
        public static bool RegisterHandler(ISecurityHandler handler)
        {
            if (_handlers.Contains(handler))
            {
                return false;
            }

            _handlers.Add(handler);
            
            return true;
        }
        /// <summary>
        /// Unregister previously registered <see cref="ISecurityHandler"/> instance
        /// </summary>
        /// <param name="handler">Handler to remove from chain of handlers</param>
        /// <returns>
        /// True on success or false if <paramref name="handler"/> if handler
        /// was not previously registered.
        /// </returns>
        public static bool UnregisterHandler(ISecurityHandler handler)
        {
            if (!_handlers.Contains(handler))
            {
                return false;
            }

            _handlers.Remove(handler);

            return true;
        }
        #endregion

        #region Internal

        #region CheckSecurity
        /// <summary>
        /// Check wheater specified invocation can proceed. Based on 
        /// security objects.
        /// </summary>
        /// <param name="invocation">Information on function to invoke</param>
        /// <returns>True wheater invocation may proceed</returns>
        /// <param name="args">Arguments to pass to the function</param>
        internal static bool CheckSecurity(Session session, IInvocation invocation, IServer server, params object[] args)
        {
            bool result = true;

            foreach (ISecurityHandler handler in _handlers)
            {
                if (handler is IRequireServerInstance)
                {
                    (handler as IRequireServerInstance).Server = server;
                }

                if (!handler.CheckSecurity(session, invocation.Method, args))
                {
                    result = false;
                    break;
                }
            }

            return result;
        }
        #endregion 

        #endregion

        #endregion
    }
}
